#include <iostream>
#include <queue>
#include <pthread.h>

static const int defaultcap = 15; 

template <class T>
class TaskQ
{
public:
    TaskQ(int maxcap = defaultcap)
        :_maxcap(maxcap)
    {
        pthread_mutex_init(&_lock,nullptr);
        pthread_cond_init(&c_cond,nullptr);
        pthread_cond_init(&p_cond,nullptr);
    }
    ~TaskQ()
    {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&c_cond);
        pthread_cond_destroy(&p_cond);

    }

    void push(const T& task)
    {
        pthread_mutex_lock(&_lock);
        while(_tq.size() == _maxcap)
        {
            pthread_cond_wait(&p_cond,&_lock);
        }
        _tq.push(task);
        
        pthread_cond_signal(&c_cond);
        pthread_mutex_unlock(&_lock);
    }

    T pop()
    {
        pthread_mutex_lock(&_lock);
        while(_tq.size() == 0)
        {
            pthread_cond_wait(&c_cond,&_lock);
            
        }
        T task = _tq.front();
        //std::cout <<" pop->" << task << std::endl;
        _tq.pop();
        pthread_cond_signal(&p_cond);
        pthread_mutex_unlock(&_lock);
        
        return task;
    }

private:
    std::queue<T> _tq;
    int _maxcap;

    pthread_mutex_t _lock;
    pthread_cond_t p_cond;
    pthread_cond_t c_cond;
};